package com.mxpio.erp.workshop.service.impl;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.date.DateUtil;
import com.mxpio.erp.common.annotation.BeanFieldOrder;
import com.mxpio.erp.common.enums.CommonEnums;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.inventory.entity.VInvLotStock;
import com.mxpio.erp.common.inventory.service.LotService;
import com.mxpio.erp.common.inventory.service.VInvLotStockService;
import com.mxpio.erp.common.inventory.vo.InvLotStockVO;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.order.service.OrderService;
import com.mxpio.erp.common.plan.entity.ManufacturePlan;
import com.mxpio.erp.common.plan.service.ManufacturePlanService;
import com.mxpio.erp.common.purchase.entity.*;
import com.mxpio.erp.common.quality.entity.*;
import com.mxpio.erp.common.technology.entity.*;
import com.mxpio.erp.common.vo.NoticeClassVo;
import com.mxpio.erp.common.workshop.entity.*;
import com.mxpio.erp.common.workshop.vo.MaterialFeedingDetailVO;
import com.mxpio.erp.common.workshop.vo.MoCostAccountingVO;
import com.mxpio.erp.common.workshop.vo.MoStortageAnalysisVO;
import com.mxpio.erp.workshop.policy.impl.ManufactureOrderSavePolicy;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.jpa.policy.impl.CrudType;
import com.mxpioframework.jpa.policy.impl.SmartCrudPolicy;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import com.mxpioframework.jpa.query.Order;
import com.mxpioframework.jpa.query.SimpleCriterion;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.mxpio.erp.common.inventory.entity.InvFlow;
import com.mxpio.erp.common.workshop.service.ManufactureOrderService;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.system.service.impl.BaseServiceImpl;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ManufactureOrderServiceImpl extends BaseServiceImpl<ManufactureOrder> implements ManufactureOrderService {

	@Autowired
	private ManufactureOrderSavePolicy manufactureOrderSavePolicy;
	@Autowired
	private ManufacturePlanService manufacturePlanService;
	@Autowired
	private OrderLineService bizOrderLineService;

	@Autowired
	private OrderService bizOrderService;
	@Autowired
	private VInvLotStockService vInvLotStockService;
	@Autowired
	private LotService lotService;
	@Override
	@Transactional
	public void handleManufactureOrderQuantity(List<ManufactureOrder> content, String accessType) {
		Map<String, BigDecimal> quantity = new HashMap<>();
		Set<String> bizNos = JpaUtil.collectId(content);
		//1.通过InvFlow计算实际执行数量
		List<InvFlow> flows = JpaUtil.linq(InvFlow.class).in("originBizNo", bizNos).list();
		for(InvFlow flow : flows){
			
			//  若流水的AccessType为参数accessType 则为执行，否则为退货
			if(accessType.equals(flow.getAccessType())){
				BigDecimal actualQuantity = quantity.get("actual:"+flow.getOriginBizNo()+flow.getOriginBizLineNo());
				if(actualQuantity == null){
					actualQuantity = BigDecimal.ZERO;
				}
				actualQuantity = actualQuantity.add(flow.getQuantity());
				quantity.put("actual:"+flow.getOriginBizNo()+flow.getOriginBizLineNo(), actualQuantity);
			}else{
				BigDecimal actualRejectQuantity = quantity.get("actualReject:"+flow.getOriginBizNo()+flow.getOriginBizLineNo());
				if(actualRejectQuantity == null){
					actualRejectQuantity = BigDecimal.ZERO;
				}
				actualRejectQuantity = actualRejectQuantity.add(flow.getQuantity());
				quantity.put("actualReject:"+flow.getOriginBizNo()+flow.getOriginBizLineNo(), actualRejectQuantity);
			}
			
		}
		
	}
	@Override
	@Transactional//从生产计划，转换为生产订单
	public Result<Object> convertMOFromMPlan(List<ManufacturePlan> planList){
		if (planList==null || planList.size()==0){
			return Result.error("提交数据为空");
		}
		List<ManufactureOrder> addList = new ArrayList<>();
		List<String> itemCodes = planList.stream().map(ManufacturePlan::getItemCode).collect(Collectors.toList());
		List<Item> dbItems = JpaUtil.linq(Item.class).in("itemCode", itemCodes).list();
		Map<String, Item> dbItemsMap = JpaUtil.index(dbItems, "itemCode");//查询提交数据中的物料
		for (ManufacturePlan plan:planList){
			if(CommonEnums.YesNo.YES.getCode().equals(plan.getOutsourceFlag())) {//如果是委外计划则不生成生产订单
				continue;
			}
			ManufactureOrder order = convertFromPlan(plan,dbItemsMap);
			if (order==null){
				return Result.error("提交数据中数据不完整，物料不存在或者计划数量为空");
			}
			addList.add(order);
			try {
				manufacturePlanService.delete(ManufacturePlan.class, plan.getPlanNo());//删除计划单
			} catch (Exception e) {
				e.printStackTrace();
				return Result.error("删除原计划单时失败，可能数据已发生变化，请刷新后重试！");
			}
		}
		save(addList,manufactureOrderSavePolicy);//保存
		return Result.OK();
	}

	private ManufactureOrder convertFromPlan(ManufacturePlan plan,Map<String, Item> dbItemsMap){
		if (plan.getQuantity()==null||plan.getQuantity().compareTo(BigDecimal.ZERO)==0|| StringUtils.isBlank(plan.getItemCode())){
			return null;
		}
		Item item = dbItemsMap.get(plan.getItemCode());
		if (item==null){
			return null;
		}
		ManufactureOrder order = new ManufactureOrder();
		order.setOrderStatus(OrderStatusEnums.OrderStatus.ORDERED.getStatusCode());//230414 默认状态由plan改为下达
		order.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
		order.setPlanner(plan.getCreateBy());
		order.setMainWorkshop(plan.getMainWorkshop());
		order.setWorkCenterCode(plan.getWorkCenterCode());
		order.setStartDate(plan.getStartDate());
		order.setEndDate(plan.getDeliverDate());
		order.setReferenceDate(new Date());//取当前日期
		order.setOrderQuantity(plan.getQuantity());
		order.setMemo(plan.getMemo());
		order.setOrderDate(new Date());
		order.setOrderType(OrderEnums.ManufactureOrderType.PLAN.getCode());//计划生产

		order.setProductItemCode(item.getItemCode());
		order.setProductItemName(item.getItemName());
		order.setProductDrawingNo(item.getDrawingNo());
		order.setItemSpec(item.getItemSpec());
		order.setUnitCode(item.getUnitCode());
		order.setCrudType(CrudType.SAVE);
		return order;
	}

	@Override
	@Transactional
	public Result<MaterialKittingAnalysisHistory> materialKittingAnalysis() {
		//清空历史分析结果，防止对本次数据产生干扰
		JpaUtil.linu(ManufactureOrder.class).set("analysisDate",null).set("analysisColor",null).set("kittingQuantity",null).isNotNull("kittingQuantity").update();
		JpaUtil.linu(ManufactureOrderItem.class).set("analysisDate",null).set("analysisColor",null).set("kittingQuantity",null).isNotNull("kittingQuantity").update();

		String today = DateUtil.formatDate(new Date());
		Date sevenDaysAfter = DateUtils.addDays(new Date(), 7);//七天之后
		Date threeDaysAfter = DateUtils.addDays(new Date(), 3);//三天之后
		Date oneDaysAfter = DateUtils.addDays(new Date(), 1);//一天之后

		Criteria criteria = Criteria.create();
		criteria.addOrder(new Order("startDate",false));//按日期升序
		List<String> statusList = new ArrayList<>();
		statusList.add(OrderStatusEnums.OrderStatus.ORDERED.getStatusCode());
		statusList.add(OrderStatusEnums.OrderStatus.PROCESSING.getStatusCode());
		statusList.add(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());//增加finish状态，考虑补料、退料对库存的影响
		//查询所有未完成的生产订单及对应明细
		List<ManufactureOrder> moList = JpaUtil.linq(ManufactureOrder.class).collect("bizNo",ManufactureOrderItem.class,"bizNo").
				in("orderStatus", statusList).
				lessThanOrEqualTo("startDate",DateUtil.endOfDay(sevenDaysAfter)).//筛选未来7天以内的订单过滤条件
				equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode()).
				where(criteria).list();
		if (moList!=null&&moList.size()>0){
			List<ManufactureOrderItem> allOrderItems = new ArrayList<>();
			for (ManufactureOrder order:moList){
				if (CollectionUtils.isNotEmpty(order.getManufactureOrderItems())){
					allOrderItems.addAll(order.getManufactureOrderItems());
				}
			}
			//处理计算字段(已执行数量等)
			NoticeClassVo pickingNoticeClazz = new NoticeClassVo(MoPickingNotice.class, MoPickingNoticeLine.class);//领/补/退
			NoticeClassVo defectiveProductsNoticeClazz = new NoticeClassVo(DefectiveProductsNotice.class, DefectiveProductsNoticeLine.class);//不良品退料
			List<NoticeClassVo> noticeClassVos = new ArrayList<>();
			noticeClassVos.add(pickingNoticeClazz);
			noticeClassVos.add(defectiveProductsNoticeClazz);
			bizOrderLineService.handleBizOrderLineQuantity(allOrderItems, noticeClassVos, OrderEnums.AccessType.OUT.getCode());

			//关联物料基础信息
			/*Set<String> itemCodeSet = allOrderItems.stream().map(ManufactureOrderItem::getItemCode).collect(Collectors.toSet());
			List<Item> itemCodeList = JpaUtil.linq(Item.class).in("itemCode", itemCodeSet).list();
			Map<String, Item> itemMap = JpaUtil.index(itemCodeList, "itemCode");*/
			//查询实时批次库存
			Criteria lotStockCri = Criteria.create();
			lotStockCri.addCriterion("quantity",Operator.GT, BigDecimal.ZERO);//增加固定过滤条件 库存大于零
			lotStockCri.addCriterion("whCode",Operator.NE, "WH0005");//增加固定过滤条件 排除废品(不合格)仓
			lotStockCri.addOrder(new Order("itemCode",false)).addOrder(new Order("lotNo",false));//排序
			List<VInvLotStock> stockList = vInvLotStockService.listByLot(lotStockCri);//实时批次库存
			if (CollectionUtils.isNotEmpty(stockList)){
				List<InvLotStockVO> stockVOList = new ArrayList<>();
				for (VInvLotStock stock:stockList){
					InvLotStockVO invLotStockVO = new InvLotStockVO();
					invLotStockVO.setWhCode(stock.getWhCode());
					invLotStockVO.setItemCode(stock.getItemCode());
					invLotStockVO.setSubLotIndex(stock.getSubLotIndex());
					invLotStockVO.setLotNo(stock.getLotNo());
					invLotStockVO.setQuantity(stock.getQuantity());
					stockVOList.add(invLotStockVO);//拷贝实时库存至对象
				}
				//计算匹配库存
				for (ManufactureOrder order:moList){
					List<ManufactureOrderItem> manufactureOrderItems = order.getManufactureOrderItems();
					if (CollectionUtils.isNotEmpty(manufactureOrderItems)){
						for (ManufactureOrderItem orderItem:manufactureOrderItems){
							orderItem.setKittingQuantity(BigDecimal.ZERO);//置零
							orderItem.setCrudType(CrudType.UPDATE);
							BigDecimal quantity = orderItem.getQuantity();//行订单需求数量
							BigDecimal actualQuantity = orderItem.getActualQuantity();//已执行数量
							BigDecimal actualRejectQuantity = orderItem.getActualRejectQuantity();//已退回数量
							actualQuantity = actualQuantity.subtract(actualRejectQuantity);//重新计算已执行数量
							BigDecimal restQuantity = quantity.subtract(actualQuantity);
							BigDecimal kittingQuantity = BigDecimal.ZERO;//齐套匹配数量
							if (restQuantity.compareTo(BigDecimal.ZERO)<=0){//20230810 由==改为<=，考虑领超的情况
								orderItem.setKittingQuantity(quantity);
							}else if (restQuantity.compareTo(BigDecimal.ZERO)>0){
								String lotNo = orderItem.getLotNo();//批次号
								String subLotIndex = orderItem.getSubLotIndex();//批次号
								String itemCode = orderItem.getItemCode();
								String whCode = orderItem.getWhCode();
								List<InvLotStockVO> matchStockList = null;
								if (StringUtils.isNotBlank(lotNo)){//指定批次的情况
									matchStockList = stockVOList.stream().filter(lotStock -> lotStock.getWhCode().equals(whCode)
											&& lotStock.getItemCode().equals(itemCode)
											&& lotStock.getLotNo().equals(lotNo)
											&& lotStock.getSubLotIndex().equals(subLotIndex))
											.collect(Collectors.toList());
								}else{//未指定批次的情况
									matchStockList = stockVOList.stream().filter(lotStock -> lotStock.getItemCode().equals(itemCode)).collect(Collectors.toList());
								}
								if (CollectionUtils.isNotEmpty(matchStockList)){
									matchStockList.sort(Comparator.comparing(InvLotStockVO::getLotNo));//按批次号升序排序(先进先出)
									for (InvLotStockVO next : matchStockList) {
										BigDecimal stockQuantity = next.getQuantity();
										if (stockQuantity.compareTo(BigDecimal.ZERO) > 0) {//有库存的情况
											if (stockQuantity.compareTo(restQuantity) >= 0) {//库存大于行数量
												kittingQuantity = kittingQuantity.add(restQuantity);
												next.setQuantity(stockQuantity.subtract(restQuantity));
												break;
											} else {
												kittingQuantity = kittingQuantity.add(stockQuantity);
												restQuantity = restQuantity.subtract(stockQuantity);
												next.setQuantity(BigDecimal.ZERO);//库存数量置
											}
										}
									}
									orderItem.setKittingQuantity(actualQuantity.add(kittingQuantity));
								}else{
									orderItem.setKittingQuantity(actualQuantity);
								}
							}
							if(orderItem.getKittingQuantity().compareTo(BigDecimal.ZERO)==0){
								orderItem.setAnalysisColor("red");
							} else if(orderItem.getKittingQuantity().compareTo(quantity)==0){
								orderItem.setAnalysisColor("green");
							} else{
								orderItem.setAnalysisColor("yellow");
							}
							orderItem.setAnalysisDate(new Date());
						}
						Set<String> analysisColorSet = manufactureOrderItems.stream().map(ManufactureOrderItem::getAnalysisColor).collect(Collectors.toSet());
						if (analysisColorSet.contains("red")){
							order.setAnalysisColor("red");
							order.setKittingQuantity(BigDecimal.ZERO);
						}else if (analysisColorSet.contains("yellow")){
							order.setAnalysisColor("yellow");
							BigDecimal orderQuantity = order.getOrderQuantity();
							List<BigDecimal> yellowQuantitys = new ArrayList<>();
							for (ManufactureOrderItem orderItem:manufactureOrderItems){
								if (StringUtils.equals("yellow",orderItem.getAnalysisColor())){
									//Item item = itemMap.get(orderItem.getItemCode());
									//Integer scale = item.getScale();
									BigDecimal olQuantity = orderItem.getQuantity();
									//BigDecimal baseNum = olQuantity.divide(orderQuantity, scale, BigDecimal.ROUND_HALF_UP);//计算单机耗用量
									BigDecimal kittingQuantity = orderItem.getKittingQuantity();
									//计算
									yellowQuantitys.add(kittingQuantity.multiply(orderQuantity).divide(olQuantity,0,BigDecimal.ROUND_DOWN));//向下取整
								}
							}
							if (yellowQuantitys.size()>1){
								yellowQuantitys.sort(Collections.reverseOrder());
								order.setKittingQuantity(yellowQuantitys.get(yellowQuantitys.size()-1));//取最小值
							}else{
								order.setKittingQuantity(yellowQuantitys.get(0));//取最小值
							}
						}else if (analysisColorSet.contains("green")){
							order.setAnalysisColor("green");
							order.setKittingQuantity(order.getOrderQuantity());
						}
						order.setAnalysisDate(new Date());
						order.setCrudType(CrudType.UPDATE);
					}
				}
				this.update(moList,new SmartCrudPolicy());//更新数据
				//记录分析结果
				MaterialKittingAnalysisHistory analysisHistory = new MaterialKittingAnalysisHistory();
				//analysisHistory.setMoBizNos(moList.stream().map(ManufactureOrder::getBizNo).collect(Collectors.joining(",")));//记录分析的订单单号
				analysisHistory.setAnalysisPeriod(today+"~"+DateUtil.formatDate(sevenDaysAfter));
				analysisHistory.setAllCntSeven(new BigDecimal(moList.size()+""));
				BigDecimal kittingCntSeven = BigDecimal.ZERO;
				for (ManufactureOrder order:moList){
					if ("green".equals(order.getAnalysisColor())){
						kittingCntSeven = kittingCntSeven.add(BigDecimal.ONE);
					}
				}
				analysisHistory.setKittingCntSeven(kittingCntSeven);
				analysisHistory.setKittingPercentSeven(kittingCntSeven.multiply(new BigDecimal("100")).divide(analysisHistory.getAllCntSeven(),2,BigDecimal.ROUND_HALF_UP));

				List<ManufactureOrder> threedaysMoList = moList.stream().filter(mo -> DateUtil.compare(mo.getStartDate(),DateUtil.endOfDay(threeDaysAfter))<=0).collect(Collectors.toList());
				if (threedaysMoList.isEmpty()){
					analysisHistory.setAllCntThree(BigDecimal.ZERO);
					analysisHistory.setKittingPercentThree(null);
					analysisHistory.setKittingCntThree(null);

					analysisHistory.setAllCntOne(BigDecimal.ZERO);
					analysisHistory.setKittingPercentOne(null);
					analysisHistory.setKittingCntOne(null);
				}else{
					analysisHistory.setAllCntThree(new BigDecimal(threedaysMoList.size()+""));
					BigDecimal kittingCntThree = BigDecimal.ZERO;
					for (ManufactureOrder order:threedaysMoList){
						if ("green".equals(order.getAnalysisColor())){
							kittingCntThree = kittingCntThree.add(BigDecimal.ONE);
						}
					}
					analysisHistory.setKittingCntThree(kittingCntThree);
					analysisHistory.setKittingPercentThree(kittingCntThree.multiply(new BigDecimal("100")).divide(analysisHistory.getAllCntThree(),2,BigDecimal.ROUND_HALF_UP));

					//继续找一天(当天)的齐套率
					List<ManufactureOrder> onedaysMoList = moList.stream().filter(mo -> DateUtil.compare(mo.getStartDate(),DateUtil.endOfDay(oneDaysAfter))<=0).collect(Collectors.toList());
					if (onedaysMoList.isEmpty()){
						analysisHistory.setAllCntOne(BigDecimal.ZERO);
						analysisHistory.setKittingPercentOne(null);
						analysisHistory.setKittingCntOne(null);
					}else{
						analysisHistory.setAllCntOne(new BigDecimal(onedaysMoList.size()+""));
						BigDecimal kittingCntOne = BigDecimal.ZERO;
						for (ManufactureOrder order:threedaysMoList){
							if ("green".equals(order.getAnalysisColor())){
								kittingCntOne = kittingCntOne.add(BigDecimal.ONE);
							}
						}
						analysisHistory.setKittingCntOne(kittingCntOne);
						analysisHistory.setKittingPercentOne(kittingCntOne.multiply(new BigDecimal("100")).divide(analysisHistory.getAllCntOne(),2,BigDecimal.ROUND_HALF_UP));
					}
				}
				JpaUtil.save(analysisHistory);
				return Result.OK(analysisHistory);
			}else{
				return Result.error("库存数据为空！");
			}
		}
		return Result.error("分析数据为空！");
	}

	@Override
	@Transactional(readOnly = true)
	public Result<List<MoStortageAnalysisVO>> shortageAnalysis(Criteria criteria) {
		if (criteria==null){
			criteria = Criteria.create();
		}
		criteria.addOrder(new Order("startDate",false));//按日期升序
		List<String> statusList = new ArrayList<>();
		statusList.add(OrderStatusEnums.OrderStatus.ORDERED.getStatusCode());
		statusList.add(OrderStatusEnums.OrderStatus.PROCESSING.getStatusCode());
		//查询所有未完成的生产订单及对应明细
		List<ManufactureOrder> moList = JpaUtil.linq(ManufactureOrder.class).collect("bizNo",ManufactureOrderItem.class,"bizNo").
				in("orderStatus", statusList).
				equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode()).
				where(criteria).list();
		if (moList!=null&&moList.size()>0){
			List<ManufactureOrderItem> allOrderItems = new ArrayList<>();
			for (ManufactureOrder order:moList){
				if (CollectionUtils.isNotEmpty(order.getManufactureOrderItems())){
					allOrderItems.addAll(order.getManufactureOrderItems());
				}
			}
			Set<String> itemCodeSet = allOrderItems.stream().map(ManufactureOrderItem::getItemCode).collect(Collectors.toSet());
			List<Item> items = JpaUtil.linq(Item.class).in("itemCode", itemCodeSet).list();
			Map<String, Item> itemMap = JpaUtil.index(items,"itemCode");//查询物料
			//处理计算字段(已执行数量等)
			NoticeClassVo pickingNoticeClazz = new NoticeClassVo(MoPickingNotice.class, MoPickingNoticeLine.class);//领/补/退
			NoticeClassVo defectiveProductsNoticeClazz = new NoticeClassVo(DefectiveProductsNotice.class, DefectiveProductsNoticeLine.class);//不良品退料
			List<NoticeClassVo> noticeClassVos = new ArrayList<>();
			noticeClassVos.add(pickingNoticeClazz);
			noticeClassVos.add(defectiveProductsNoticeClazz);
			bizOrderLineService.handleBizOrderLineQuantity(allOrderItems, noticeClassVos, OrderEnums.AccessType.OUT.getCode());

			//关联物料基础信息
			/*Set<String> itemCodeSet = allOrderItems.stream().map(ManufactureOrderItem::getItemCode).collect(Collectors.toSet());
			List<Item> itemCodeList = JpaUtil.linq(Item.class).in("itemCode", itemCodeSet).list();
			Map<String, Item> itemMap = JpaUtil.index(itemCodeList, "itemCode");*/
			//查询实时批次库存
			Criteria lotStockCri = Criteria.create();
			lotStockCri.addCriterion("quantity",Operator.GT, BigDecimal.ZERO);//增加固定过滤条件 库存大于零
			lotStockCri.addCriterion("whCode",Operator.NE, "WH0005");//增加固定过滤条件 排除废品(不合格)仓
			lotStockCri.addOrder(new Order("itemCode",false)).addOrder(new Order("lotNo",false));//排序
			List<VInvLotStock> stockList = vInvLotStockService.listByLot(lotStockCri);//实时批次库存
			if (CollectionUtils.isNotEmpty(stockList)){
				List<InvLotStockVO> stockVOList = new ArrayList<>();
				for (VInvLotStock stock:stockList){
					InvLotStockVO invLotStockVO = new InvLotStockVO();
					invLotStockVO.setWhCode(stock.getWhCode());
					invLotStockVO.setItemCode(stock.getItemCode());
					invLotStockVO.setLotNo(stock.getLotNo());
					invLotStockVO.setSubLotIndex(stock.getSubLotIndex());
					invLotStockVO.setQuantity(stock.getQuantity());
					stockVOList.add(invLotStockVO);//拷贝实时库存至对象，库存数量有冲减计算，防止直接修改VInvLotStock对象带来问题
				}
				//计算匹配库存
				for (ManufactureOrder order:moList){
					List<ManufactureOrderItem> manufactureOrderItems = order.getManufactureOrderItems();
					if (CollectionUtils.isNotEmpty(manufactureOrderItems)){
						for (ManufactureOrderItem orderItem:manufactureOrderItems){
							orderItem.setMo(order);//关联主单对象
							orderItem.setKittingQuantity(BigDecimal.ZERO);//置零
							BigDecimal quantity = orderItem.getQuantity();//行订单需求数量
							BigDecimal actualQuantity = orderItem.getActualQuantity();//已执行数量
							BigDecimal actualRejectQuantity = orderItem.getActualRejectQuantity();//已退回数量
							actualQuantity = actualQuantity.subtract(actualRejectQuantity);//重新计算已执行数量
							BigDecimal restQuantity = quantity.subtract(actualQuantity);
							BigDecimal kittingQuantity = BigDecimal.ZERO;//齐套匹配数量
							if (restQuantity.compareTo(BigDecimal.ZERO)<=0){//20230810 由==改为<=，考虑领超的情况
								orderItem.setKittingQuantity(quantity);
							}else if (restQuantity.compareTo(BigDecimal.ZERO)>0){
								String lotNo = orderItem.getLotNo();//批次号
								String subLotIndex = orderItem.getSubLotIndex();//批次索引号
								String itemCode = orderItem.getItemCode();
								String whCode = orderItem.getWhCode();
								List<InvLotStockVO> matchStockList = null;
								if (StringUtils.isNotBlank(lotNo)){//指定批次的情况
									matchStockList = stockVOList.stream().filter(lotStock -> lotStock.getWhCode().equals(whCode)
											&& lotStock.getItemCode().equals(itemCode)
											&& lotStock.getLotNo().equals(lotNo)
											&& lotStock.getSubLotIndex()
											.equals(subLotIndex)).collect(Collectors.toList());
								}else{//未指定批次的情况
									matchStockList = stockVOList.stream().filter(lotStock -> lotStock.getItemCode().equals(itemCode)).collect(Collectors.toList());
								}
								if (CollectionUtils.isNotEmpty(matchStockList)){
									matchStockList.sort(Comparator.comparing(InvLotStockVO::getLotNo));//按批次号升序排序(先进先出)
									for (InvLotStockVO next : matchStockList) {
										BigDecimal stockQuantity = next.getQuantity();
										if (stockQuantity.compareTo(BigDecimal.ZERO) > 0) {//有库存的情况
											if (stockQuantity.compareTo(restQuantity) >= 0) {//库存大于行数量
												kittingQuantity = kittingQuantity.add(restQuantity);
												next.setQuantity(stockQuantity.subtract(restQuantity));
												break;
											} else {
												kittingQuantity = kittingQuantity.add(stockQuantity);
												restQuantity = restQuantity.subtract(stockQuantity);
												next.setQuantity(BigDecimal.ZERO);//库存数量置
											}
										}
									}
									orderItem.setKittingQuantity(actualQuantity.add(kittingQuantity));
								}else{
									orderItem.setKittingQuantity(actualQuantity);
								}
							}
							if(orderItem.getKittingQuantity().compareTo(BigDecimal.ZERO)==0){
								orderItem.setAnalysisColor("red");
							} else if(orderItem.getKittingQuantity().compareTo(quantity)==0){
								orderItem.setAnalysisColor("green");
							} else{
								orderItem.setAnalysisColor("yellow");
							}
						}
					}
				}
				List<ManufactureOrderItem> lackDetails = allOrderItems.stream().filter(manufactureOrderItem -> !manufactureOrderItem.getAnalysisColor().equals("green")).collect(Collectors.toList());
				List<MoStortageAnalysisVO> returnList = new ArrayList<>();
				if (lackDetails.size()>0){
					Map<String, List<ManufactureOrderItem>> groupMap = lackDetails.stream().collect(Collectors.groupingBy(ManufactureOrderItem::getItemCode));
					for (String itemCode:groupMap.keySet()){
						if (!itemMap.containsKey(itemCode)||itemMap.get(itemCode)==null){
							return Result.error("订单bom明细物料【"+itemCode+"】不存在！！！");
						}
						Item one = itemMap.get(itemCode);
						List<ManufactureOrderItem> manufactureOrderItemList = groupMap.get(itemCode);
						MoStortageAnalysisVO moStortageAnalysisVO = new MoStortageAnalysisVO();
						moStortageAnalysisVO.setItemCode(one.getItemCode());
						moStortageAnalysisVO.setItemName(one.getItemName());
						moStortageAnalysisVO.setItemSpec(one.getItemSpec());
						moStortageAnalysisVO.setDrawingNo(one.getDrawingNo());
						moStortageAnalysisVO.setItemGroupCode(one.getItemGroupCode());
						moStortageAnalysisVO.setUnitCode(one.getUnitCode());
						moStortageAnalysisVO.setItemSource(one.getItemSource());
						List<String> bizNos = new ArrayList<>();
						List<String> prodDrawingNos = new ArrayList<>();
						BigDecimal orderQuantitySum = BigDecimal.ZERO;
						//BigDecimal stockQuantitySum = BigDecimal.ZERO;
						BigDecimal lackQuantitySum = BigDecimal.ZERO;
						for (ManufactureOrderItem it:manufactureOrderItemList){
							if (!bizNos.contains(it.getBizNo())){
								bizNos.add(it.getBizNo());
							}
							if (!prodDrawingNos.contains(it.getMo().getProductDrawingNo())){
								prodDrawingNos.add(it.getMo().getProductDrawingNo());
							}
							orderQuantitySum = orderQuantitySum.add(it.getQuantity());
							lackQuantitySum = lackQuantitySum.add(it.getQuantity().subtract(it.getKittingQuantity()));
						}
						moStortageAnalysisVO.setOrderQuantity(orderQuantitySum);
						moStortageAnalysisVO.setLackQuantity(lackQuantitySum);
						BigDecimal stockQuantity = stockList.stream().filter(item -> item.getItemCode().equals(itemCode)).collect(Collectors.toList()).stream().map(VInvLotStock::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
						moStortageAnalysisVO.setStockQuantity(stockQuantity);
						moStortageAnalysisVO.setMoBizNos(bizNos.stream().map(String::valueOf).collect(Collectors.joining(",")));
						moStortageAnalysisVO.setMoProdDrawingNos(prodDrawingNos.stream().map(String::valueOf).collect(Collectors.joining(",")));
						returnList.add(moStortageAnalysisVO);
					}
				}
				return Result.OK("分析完成！",returnList);
			}else{
				return Result.error("库存数据为空，无法分析缺件！");
			}
		}
		return Result.error("分析数据为空！");
	}

	@Override
	@Transactional
	public Result<List<MaterialFeedingDetailVO>> materialFeedingAnalysis(String itemCode) {
		List<MaterialFeedingDetailVO> returnResultList = new ArrayList<>();
		//查采购数据
		List<PurchaseOrderLine> purchaseOrderLines = JpaUtil.linq(PurchaseOrderLine.class)
				.collect("bizNo", PurchaseOrder.class, "bizNo")
				.exists(PurchaseOrder.class)
				.equalProperty("bizNo", "bizNo")
				.notEqual("closeStatus", OrderStatusEnums.CloseStatus.CLOSED.getStatusCode())
				.equal("bpmnStatus", OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())
				.notEqual("orderStatus", OrderStatusEnums.OrderStatus.CLEARED.getStatusCode())
				.end()
				.equal("itemCode", itemCode)
				.list();
		if (purchaseOrderLines.size()>0){
			NoticeClassVo receivingNoticeClazz = new NoticeClassVo(ReceivingNotice.class, ReceivingNoticeLine.class);
			NoticeClassVo rejectNoticeClazz = new NoticeClassVo(RejectNotice.class, RejectNoticeLine.class);
			NoticeClassVo inQualityOrderClazz = new NoticeClassVo(InQualityOrder.class, InQualityOrderLine.class);//增加入库验收单 数据统计
			List<NoticeClassVo> noticeClassVos = new ArrayList<>();
			noticeClassVos.add(receivingNoticeClazz);
			noticeClassVos.add(rejectNoticeClazz);
			noticeClassVos.add(inQualityOrderClazz);
			bizOrderLineService.handleBizOrderLineQuantity(purchaseOrderLines, noticeClassVos, OrderEnums.AccessType.IN.getCode());
			for (PurchaseOrderLine line:purchaseOrderLines){
				MaterialFeedingDetailVO vo = new MaterialFeedingDetailVO();
				vo.setOrderType("采购订单");
				vo.setBizNo(line.getBizNo());
				vo.setLineNo(line.getLineNo());
				vo.setSupplysCode(line.getPurchaseOrder().getPnCode());
				vo.setSupplysName(line.getPurchaseOrder().getPnName());
				vo.setOrderQuantity(line.getQuantity());
				vo.setPlanQuantity(line.getPlanQuantity());
				vo.setActualQuantity(line.getActualQuantity().subtract(line.getActualRejectQuantity()));
				returnResultList.add(vo);
			}
		}
		//生产订单
		List<ManufactureOrder> manufactureOrders = JpaUtil.linq(ManufactureOrder.class)
				.notEqual("closeStatus", OrderStatusEnums.CloseStatus.CLOSED.getStatusCode())
				//.equal("bpmnStatus", OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())
				.notEqual("orderStatus", OrderStatusEnums.OrderStatus.CLEARED.getStatusCode())
				.equal("productItemCode", itemCode)
				.list();
		if (manufactureOrders.size()>0){
			NoticeClassVo moInNoticeClazz = new NoticeClassVo(MoInNotice.class, MoInNoticeLine.class);//生产入库通知单
			NoticeClassVo moInQualityOrderClazz = new NoticeClassVo(MoInQualityOrder.class, MoInQualityOrderLine.class);//生产入库检验单
			List<NoticeClassVo> noticeClassVos = new ArrayList<>();
			noticeClassVos.add(moInNoticeClazz);
			noticeClassVos.add(moInQualityOrderClazz);
			bizOrderService.handleBizOrderQuantity(manufactureOrders,noticeClassVos,OrderEnums.AccessType.IN.getCode());

			Map<String,WorkShop> workShopMap = new HashMap<>();
			for (ManufactureOrder mo:manufactureOrders){
				MaterialFeedingDetailVO vo = new MaterialFeedingDetailVO();
				vo.setOrderType("生产订单");
				vo.setBizNo(mo.getBizNo());
				vo.setLineNo("0");
				vo.setSupplysCode(mo.getMainWorkshop());
				if (!workShopMap.containsKey(mo.getMainWorkshop())){
					WorkShop one = JpaUtil.linq(WorkShop.class).equal("workShopCode",mo.getMainWorkshop()).findOne();
					if (one!=null){
						workShopMap.put(mo.getMainWorkshop(),one);
						vo.setSupplysName(one.getWorkShopName());
					}
				}else{
					WorkShop workShop = workShopMap.get(mo.getMainWorkshop());
					vo.setSupplysName(workShop.getWorkShopName());
				}
				vo.setOrderQuantity(mo.getOrderQuantity());
				vo.setPlanQuantity(mo.getPlanQuantity());
				vo.setActualQuantity(mo.getActualQuantity());
				returnResultList.add(vo);
			}
		}

		//委外
		List<OutsourceOrder> outsourceOrders = JpaUtil.linq(OutsourceOrder.class)
				.notEqual("closeStatus", OrderStatusEnums.CloseStatus.CLOSED.getStatusCode())
				//.equal("bpmnStatus", OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())
				.notEqual("orderStatus", OrderStatusEnums.OrderStatus.CLEARED.getStatusCode())
				.equal("productItemCode", itemCode)
				.list();

		if (outsourceOrders.size()>0){
			NoticeClassVo moInNoticeClazz = new NoticeClassVo(OoInNotice.class, OoInNoticeLine.class);//委外入库通知单
			NoticeClassVo moInQualityOrderClazz = new NoticeClassVo(OoInQualityOrder.class, OoInQualityOrderLine.class);//委外入库检验单
			List<NoticeClassVo> noticeClassVos = new ArrayList<>();
			noticeClassVos.add(moInNoticeClazz);
			noticeClassVos.add(moInQualityOrderClazz);
			bizOrderService.handleBizOrderQuantity(outsourceOrders,noticeClassVos,OrderEnums.AccessType.IN.getCode());

			Map<String,WorkShop> workShopMap = new HashMap<>();
			for (OutsourceOrder oo:outsourceOrders){
				MaterialFeedingDetailVO vo = new MaterialFeedingDetailVO();
				vo.setOrderType("委外订单");
				vo.setBizNo(oo.getBizNo());
				vo.setLineNo("0");
				vo.setSupplysCode(oo.getPnCode());
				vo.setSupplysName(oo.getPnName());
				/*if (!workShopMap.containsKey(oo.getMainWorkshop())){
					WorkShop one = JpaUtil.linq(WorkShop.class).equal("workShopCode",oo.getMainWorkshop()).findOne();
					if (one!=null){
						workShopMap.put(oo.getMainWorkshop(),one);
						vo.setSupplysName(one.getWorkShopName());
					}
				}else{
					WorkShop workShop = workShopMap.get(oo.getMainWorkshop());
					vo.setSupplysName(workShop.getWorkShopName());
				}*/
				vo.setOrderQuantity(oo.getOrderQuantity());
				vo.setPlanQuantity(oo.getPlanQuantity());
				vo.setActualQuantity(oo.getActualQuantity());
				returnResultList.add(vo);
			}
		}
		return Result.OK(returnResultList);
	}

	@Override
	@Transactional
	public Result<Page<MoCostAccountingVO>> costAccounting(Criteria c, Integer pageSize, Integer pageNo) throws IllegalAccessException {
		Pageable page = PageRequest.of(pageNo-1, pageSize);
		String beginDate = "";
		String endDate = "";
		String bizNo = "";
		String whereStr = "";
		String dateFilterStr = "";
		int startIndex = (pageNo-1)*pageSize;
		int endIndex = pageNo*pageSize;

		if (c.getCriterions()!=null&&c.getCriterions().size()>0){
			List<Object> criterions = c.getCriterions();
			for (Object obj:criterions){
				if (obj instanceof SimpleCriterion){
					SimpleCriterion criterion = (SimpleCriterion) obj;
					if (criterion.getFieldName().equals("beginDate")){
						beginDate = (String) criterion.getValue();
					}else if (criterion.getFieldName().equals("endDate")){
						endDate = (String) criterion.getValue();
					}else if (criterion.getFieldName().equals("bizNo")){
						bizNo = (String) criterion.getValue();
						whereStr = " where p2.biz_no_ ='"+bizNo+"' ";
					}
				}
			}
		}
		if (StringUtils.isNotBlank(beginDate)&&StringUtils.isNotBlank(endDate)){
			dateFilterStr = "  and date(t2.create_time) between '"+beginDate+"' and '"+endDate+"' ";
		}else if (StringUtils.isNotBlank(beginDate)){
			dateFilterStr = "  and date(t2.create_time) >= '"+beginDate+"' ";
		}else if (StringUtils.isNotBlank(endDate)){
			dateFilterStr = "  and date(t2.create_time) <= '"+endDate+"' ";
		}
		//查询视图，注意，如果有字段 增删，对应的MoCostAccountingVO对象中的字段也需要调整，特别注意注解的顺序值，对应不上则会写入失败
		String querySqlBase =" " +
				"select  " +
				"  p2.biz_no_,  " +
				"  p2.product_item_code_,  " +
				"  p2.product_item_name_ ,  " +
				"  p2.product_item_spec_,  " +
				"  p2.product_drawing_no_ ,  " +
				"  p2.prod_in_quantity_ ,  " +
				"  p1.item_code_,  " +
				"  p1.item_name_ ,  " +
				"  p1.item_spec_ ,  " +
				"  p1.drawing_no_ ,  " +
				"  p1.item_group_code_ ,  " +
				"  p1.item_group_name_,  " +
				"  p1.unit_code_ ,  " +
				"  p1.unit_code_name_,  " +
				"  p1.wh_code_,  " +
				"  p1.wh_name_ ,  " +
				"  p1.basenum,  " +
				"  p1.picking_quantity_,  " +
				"  case  " +
				"    when p1.picking_quantity_ = 0 then  " +
				"    0  " +
				"    when ifnull(p2.prod_in_quantity_, 0)* p1.basenum >= p1.picking_quantity_ then  " +
				"    p1.picking_quantity_  " +
				"    else (ifnull(p2.prod_in_quantity_, 0)* p1.basenum)+0  " +
				"  end as account_quantity_  ," +
				"  p2.main_workshop_ , " +
				"  p3.procedure_name_ , " +
				"  p4.prod_in_quantity_sum_, " +
				"  p1.picking_quantity_-ifnull(p4.prod_in_quantity_sum_, 0)*p1.basenum as picking_quantity_last_ , " +
				"  p1.last_picking_time_ " +
				"from  " +
				"  (  " +
				"  select  " +
				"    bm.biz_no_ ,  " +
				"    bm.line_no_ ,  " +
				"    bm.consumption as basenum,  " +
				"    bm.line_quantity_, " +
				"    bm.item_code_,  " +
				"    bm.item_name_ ,  " +
				"    bm.drawing_no_ ,  " +
				"    bm.item_spec_ ,  " +
				"    bm.item_group_code_ ,  " +
				"    bm.item_group_name_,  " +
				"    bm.unit_code_ ,  " +
				"    bm.unit_code_name_,  " +
				"    bm.wh_code_,  " +
				"    bm.wh_name_ ,  " +
				"    ifnull(bomi.picking_quantity_, 0) as picking_quantity_  , " +
				"    bomi.last_picking_time_ " +
				"  from  " +
				"    (  " +
				"    select  " +
				"      mi.biz_no_ ,  " +
				"      mi.line_no_ ,  " +
				"      ROUND(mi.quantity_ / m.order_qantity_,2) as consumption,  " +
				"      mi.quantity_ as line_quantity_,"+
				"      mi.item_code_,  " +
				"      mi.item_name_ ,  " +
				"      mi.drawing_no_ ,  " +
				"      mi.item_spec_ ,  " +
				"      mi.item_group_code_ ,  " +
				"      ig.group_name_ as item_group_name_,  " +
				"      mi.unit_code_ ,  " +
				"      di.item_text_ as unit_code_name_,  " +
				"      mi.wh_code_,  " +
				"      wh.wh_name_  " +
				"    from  " +
				"      mb_erp_workshop_mo_item mi  " +
				"    left join mb_erp_workshop_mo m  " +
				"            on  " +
				"      m.biz_no_ = mi.biz_no_  " +
				"    left join mb_erp_inventory_item_group ig  " +
				"            on  " +
				"      mi.item_group_code_ = ig.group_code_  " +
				"    left join mb_erp_inv_warehouse wh  " +
				"      on  " +
				"      mi.wh_code_ = wh.wh_code_  " +
				"    left join mb_dict_item di  " +
				"            on  " +
				"      di.dict_id_ =  " +
				"            (  " +
				"      select  " +
				"        id_  " +
				"      from  " +
				"        mb_dict  " +
				"      where  " +
				"        dict_code_ = 'ERP_TECH_UNIT_CODE')  " +
				"      and di.item_value_ = mi.unit_code_ ) bm  " +
				"  left join  " +
				"                (  " +
				"    select  " +
				"      ff.biz_no_,  " +
				"      ff.origin_biz_line_no_,  " +
				"      sum(if((`ff`.`access_type_` = 'out'), `ff`.`quantity_`,(0 - `ff`.`quantity_`))) as picking_quantity_ ," +
				"      max(ff.picking_time_) as last_picking_time_ " +
				"    from  " +
				"      (  " +
				"      select  " +
				"        t2.quantity_ ,  " +
				"		 t2.access_type_, " +
				"        t0.biz_no_ as biz_no_,  " +
				"        t2.create_time as picking_time_,  " +
				"        t2.origin_biz_line_no_  " +
				"      from  " +
				"        mb_erp_workshop_mo t0  " +
				"      inner join mb_erp_inv_flow t2  " +
				"                        on  " +
				"        t0.biz_no_ = t2.origin_biz_no_  " +
				"      inner join mb_erp_inv_wo t3  " +
				"                        on  " +
				"        t2.wo_biz_no_ = t3.biz_no_  " +
				"      where  " +
				"        t3.wo_type_ in ('41','15','42','16') )ff  " +
				"    group by  " +
				"      ff.biz_no_,  " +
				"      ff.origin_biz_line_no_ ) bomi  " +
				"                        on  " +
				"    bm.biz_no_ = bomi.biz_no_  " +
				"    and bm.line_no_ = bomi.origin_biz_line_no_ ) p1  " +
				"inner join  " +
				"                    (  " +
				"  select  " +
				"    biz_no_,  " +
				"    product_item_code_,  " +
				"    product_item_name_ ,  " +
				"    product_drawing_no_ ,  " +
				"    item_spec_ as product_item_spec_, " +
				"	 main_workshop_, " +
				"    sum(if((`pd`.`access_type_` = 'in'), `pd`.`quantity_`,(0 - `pd`.`quantity_`))) as `prod_in_quantity_`  " +
				"  from  " +
				"    (  " +
				"    select  " +
				"      t2.item_code_ ,  " +
				"      t2.quantity_ ,  " +
				"      t2.access_type_,  " +
				"      t3.wo_type_ ,  " +
				"      t2.wo_biz_no_ ,  " +
				"      t2.wo_biz_line_no_ ,  " +
				"      t0.biz_no_ ,  " +
				"      '生产订单' as origin_biz_type_,  " +
				"      t0.order_status_ ,  " +
				"      t0.order_qantity_,  " +
				"      t0.product_item_code_ ,  " +
				"      t0.product_item_name_ ,  " +
				"      t0.product_drawing_no_ ,  " +
				"      t0.item_spec_ ,  " +
				"	   t0.main_workshop_, " +
				"      t2.create_time as stock_time_  " +
				"    from  " +
				"      mb_erp_workshop_mo t0  " +
				"    inner join mb_erp_inv_flow t2  " +
				"                            on  " +
				"      t0.biz_no_ = t2.origin_biz_no_  " +
				"    inner join mb_erp_inv_wo t3  " +
				"                            on  " +
				"      t2.wo_biz_no_ = t3.biz_no_  " +
				"    where  " +
				"      t3.wo_type_ = '30'  " + dateFilterStr +
				"     ) pd  " +
				"  group by  " +
				"    pd.biz_no_,  " +
				"    product_item_code_,  " +
				"    pd.product_item_name_ ,  " +
				"    pd.product_drawing_no_ ,  " +
				"	 pd.main_workshop_, " +
				"    pd.item_spec_ )p2  " +
				"                        on  " +
				"  p1.biz_no_ = p2.biz_no_ " +
				"  inner join (  " +
				"  select  " +
				"    biz_no_,  " +
				"    sum(if((`pd`.`access_type_` = 'in'), `pd`.`quantity_`,(0 - `pd`.`quantity_`))) as `prod_in_quantity_sum_`  " +
				"  from  " +
				"    (  " +
				"    select  " +
				"      t2.quantity_ ,  " +
				"      t2.access_type_,  " +
				"      t0.biz_no_   " +
				"    from  " +
				"      mb_erp_workshop_mo t0  " +
				"    inner join mb_erp_inv_flow t2 on  " +
				"      t0.biz_no_ = t2.origin_biz_no_  " +
				"    inner join mb_erp_inv_wo t3 on  " +
				"      t2.wo_biz_no_ = t3.biz_no_  " +
				"    where  " +
				"      t3.wo_type_ = '30') pd  " +
				"  group by  " +
				"    pd.biz_no_)p4 on  " +
				"  p4.biz_no_ = p2.biz_no_ " +
				"  left join mb_erp_technology_workshop p3 on p3.work_shop_code_ = p2.main_workshop_ "+
				whereStr;
		String querySql = querySqlBase +" limit "+startIndex+","+endIndex;
		int count = JpaUtil.nativeQuery(querySqlBase).getResultList().size();
		List resultList = JpaUtil.nativeQuery(querySql).getResultList();
		List<MoCostAccountingVO> accountingVOS = new ArrayList<>();
		if(resultList!=null&&resultList.size()>0){
			Field[] fi = MoCostAccountingVO.class.getDeclaredFields();
			for (Object obj:resultList){
				Object[] object = (Object[])obj;
				MoCostAccountingVO vo = new MoCostAccountingVO();
				for (Field field:fi){
					if (field.isAnnotationPresent(BeanFieldOrder.class)){
						BeanFieldOrder annotation = field.getAnnotation(BeanFieldOrder.class);
						int order = annotation.order();
						field.setAccessible(true);
						field.set(vo,object[order]);
					}
				}
				accountingVOS.add(vo);
			}
		}
		return Result.OK(new PageImpl<>(accountingVOS,page,count));
	}

	@Override
	@Transactional
	public Result<? extends com.mxpio.erp.common.jpa.model.Order> clearOrder(String bizNo) {
		ManufactureOrder mo = this.getById(ManufactureOrder.class,bizNo);
		if(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode().equals(mo.getOrderStatus())){
			//校验明细 是否存在未执行完毕的退料、补料、领料记录
			Criteria c = Criteria.create().addCriterion("bizNo", Operator.EQ, bizNo);
			List<ManufactureOrderItem> manufactureOrderItems = JpaUtil.linq(ManufactureOrderItem.class).where(c).list();
			if (manufactureOrderItems.size()>0){
				//计算数量字段
				NoticeClassVo pickingNoticeClazz = new NoticeClassVo(MoPickingNotice.class, MoPickingNoticeLine.class);//领/补/退
				NoticeClassVo defectiveProductsNoticeClazz = new NoticeClassVo(DefectiveProductsNotice.class, DefectiveProductsNoticeLine.class);//不良品退料
				List<NoticeClassVo> noticeClassVos = new ArrayList<>();
				noticeClassVos.add(pickingNoticeClazz);
				noticeClassVos.add(defectiveProductsNoticeClazz);
				bizOrderLineService.handleBizOrderLineQuantity(manufactureOrderItems, noticeClassVos, OrderEnums.AccessType.OUT.getCode());
				for (ManufactureOrderItem orderItem:manufactureOrderItems){
					if ((orderItem.getPlanQuantity()!=null &&orderItem.getPlanQuantity().compareTo(BigDecimal.ZERO)!=0)
							|| (orderItem.getPlanRejectQuantity()!=null && orderItem.getPlanRejectQuantity().compareTo(BigDecimal.ZERO)!=0)){
						return Result.error("订单行存在未执行完毕的领、退、补料记录，无法结算订单。");
					}
				}
			}
			//校验订单主单
			List<ManufactureOrder> orderList = new ArrayList<>();
			orderList.add(mo);
			NoticeClassVo moInNoticeClazz = new NoticeClassVo(MoInNotice.class, MoInNoticeLine.class);//生产入库通知单
			NoticeClassVo moInQualityOrderClazz = new NoticeClassVo(MoInQualityOrder.class, MoInQualityOrderLine.class);//生产入库检验单
			List<NoticeClassVo> noticeClassVos = new ArrayList<>();
			noticeClassVos.add(moInNoticeClazz);
			noticeClassVos.add(moInQualityOrderClazz);
			bizOrderService.handleBizOrderQuantity(orderList,noticeClassVos,OrderEnums.AccessType.IN.getCode());
			if (mo.getPlanQuantity()!=null && mo.getPlanQuantity().compareTo(BigDecimal.ZERO) !=0){
				return Result.error("订单存在未执行完成的产品入库记录，无法结算订单。");
			}
			//统计没有用完的领料，自动生成退料单
			/*if (!manufactureOrderItems.isEmpty()){
				BigDecimal actualQuantity = mo.getActualQuantity();//实际报工数量
				BigDecimal orderQuantity = mo.getOrderQuantity();//订单数量
				List<InvFlowSummaryVo> returnBomItemFlowList = new ArrayList<>();
				for (ManufactureOrderItem orderItem:manufactureOrderItems){
					BigDecimal lineQuantity = orderItem.getQuantity();
					BigDecimal lineActualQuantity = orderItem.getActualQuantity();
					BigDecimal consumeQuantity = actualQuantity.multiply(lineQuantity).divide(orderQuantity, 6, BigDecimal.ROUND_HALF_UP);//成套耗用量
					orderItem.setConsumeQuantity(consumeQuantity);
					if (lineActualQuantity.compareTo(consumeQuantity)>0){//多领
						BigDecimal returnQuantity = lineActualQuantity.subtract(consumeQuantity);
						Collection<InvFlowSummaryVo> executedInvFlows = lotService.getExecutedInvFlows(mo.getBizNo(), orderItem.getLineNo(), OrderEnums.AccessType.OUT.getCode(), null);
						List<InvFlowSummaryVo> excutedFlowList = new ArrayList(executedInvFlows);
						Collections.sort(excutedFlowList, new Comparator<InvFlowSummaryVo>() {
							@Override
							public int compare(InvFlowSummaryVo o1, InvFlowSummaryVo o2) {
								long result = o1.getCreateTime().getTime()-o2.getCreateTime().getTime();
								if (result<0){
									return 1;//降序
								}else if(result>0){
									return -1;
								}else{
									return 0;
								}
							}
						});
						for (InvFlowSummaryVo vo:excutedFlowList){
							BigDecimal flowQuantity = vo.getQuantity();
							if (returnQuantity.compareTo(flowQuantity)>0){
								returnQuantity = returnQuantity.subtract(flowQuantity);
								returnBomItemFlowList.add(vo);
							}else{
								vo.setQuantity(returnQuantity);
								returnBomItemFlowList.add(vo);
								break;//跳出循环
							}
						}
					}
				}
				//分组 产生生产退料通知单以及仓单，及自动执行流水
				if (!returnBomItemFlowList.isEmpty()){
					Set<String> itemCodeSet = returnBomItemFlowList.stream().map(InvFlowSummaryVo::getItemCode).collect(Collectors.toSet());
					List<Item> itemList = JpaUtil.linq(Item.class).in("itemCode", itemCodeSet).list();
					Map<Object, Item> itemMap = JpaUtil.index(itemList, "itemCode");

					Map<String, List<InvFlowSummaryVo>> whMap = returnBomItemFlowList.stream().collect(Collectors.groupingBy(InvFlowSummaryVo::getWhCode));
					boolean automatic = false;//自动化执行标志
					for (String whcode:whMap.keySet()){
						MoPickingNotice notice = new MoPickingNotice();
						//关联生产订单业务字段
						notice.setProductItemCode(mo.getProductItemCode());
						notice.setProductItemName(mo.getProductItemName());
						notice.setOrderQuantity(mo.getOrderQuantity());
						notice.setProductDrawingNo(mo.getProductDrawingNo());
						notice.setMainWorkshop(mo.getMainWorkshop());

						notice.setBizOrderNo(mo.getBizNo());
						notice.setNoticeDate(new Date());
						notice.setWhCode(whcode);
						notice.setAccessType(OrderEnums.AccessType.IN.getCode());
						notice.setPickingType(NoticeStatusEnums.NoticeType.MO_M_IN.getCode());
						if (automatic){
							notice.setNoticeStatus(NoticeStatusEnums.NoticeStatus.CONFIRM.getStatusCode());
						}else{
							notice.setNoticeStatus(NoticeStatusEnums.NoticeStatus.CREATE.getStatusCode());
						}
						JpaUtil.save(notice);//保存退料通知单
						List<InvFlowSummaryVo> invFlowSummaryVos = whMap.get(whcode);
						int lineNo = 0;
						List<MoPickingNoticeLine> lineList = new ArrayList<>();
						for (InvFlowSummaryVo vo:invFlowSummaryVos){
							lineNo++;
							MoPickingNoticeLine noticeLine = new MoPickingNoticeLine();
							noticeLine.setOriginBizLineNo(vo.getOriginBizLineNo());
							noticeLine.setOriginBizNo(vo.getOriginBizNo());
							noticeLine.setItemCode(vo.getItemCode());
							noticeLine.setItemName(vo.getItemName());
							noticeLine.setItemSpec(vo.getItemSpec());
							noticeLine.setDrawingNo(vo.getDrawingNo());
							noticeLine.setUnitCode(vo.getUnitCode());
							noticeLine.setNoticeNo(notice.getNoticeNo());
							noticeLine.setQuantity(vo.getQuantity());
							noticeLine.setLotNo(vo.getLotNo());
							noticeLine.setSubLotIndex(vo.getSubLotIndex());
							noticeLine.setLineNo(lineNo+"");
							JpaUtil.save(noticeLine);
							lineList.add(noticeLine);
						}
						if (automatic){//自动生成仓单且自动执行
							WarehouseOrder wo = new WarehouseOrder();
							wo.setAccessType(notice.getAccessType());
							wo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
							wo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
							wo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
							wo.setOrderDate(new Date());
							wo.setOriginBizNo(notice.getBizOrderNo());
							wo.setWhCode(notice.getWhCode());
							wo.setWoType(notice.getPickingType());
							wo.setOriginNoticeNo(notice.getNoticeNo());//关联noticeno字段
							wo.setExecutor("8888");//自动化助手，默认指定用户
							wo.setExecuteTime(new Date());
							JpaUtil.save(wo);
							int wolineNo = 0;
							for (MoPickingNoticeLine noticeLine:lineList){
								wolineNo++;
								WarehouseOrderLine line = new WarehouseOrderLine();
								line.setWhCode(wo.getWhCode());
								line.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
								Item item = itemMap.get(noticeLine.getItemCode());
								if (item!=null){
									line.setItemGroupCode(item.getItemGroupCode());
								}
								line.setItemCode(noticeLine.getItemCode());
								line.setItemName(noticeLine.getItemName());
								line.setItemSpec(noticeLine.getItemSpec());
								line.setUnitCode(noticeLine.getUnitCode());
								line.setDrawingNo(noticeLine.getDrawingNo());
								line.setQuantity(noticeLine.getQuantity());
								line.setBizNo(wo.getBizNo());
								line.setLineNo(wolineNo+"");
								line.setOriginBizNo(wo.getOriginBizNo());
								line.setOriginBizLineNo(noticeLine.getOriginBizLineNo());
								line.setSort(wolineNo+"");
								line.setLotNo(noticeLine.getLotNo());
								line.setSubLotIndex(noticeLine.getSubLotIndex());
								line.setOriginNoticeNo(notice.getNoticeNo());
								line.setOriginNoticeLineNo(noticeLine.getLineNo());
								JpaUtil.save(line);

								//自动执行，生成流水
								InvFlow inFlow = new InvFlow();
								inFlow.setAccessType(wo.getAccessType());
								inFlow.setItemCode(line.getItemCode());
								inFlow.setWhCode(wo.getWhCode());
								inFlow.setQuantity(line.getQuantity());
								inFlow.setMemo(wo.getMemo());
								inFlow.setOriginBizNo(wo.getOriginBizNo());
								inFlow.setOriginBizType(wo.getOriginBizType());
								inFlow.setOriginBizLineNo(line.getOriginBizLineNo());
								inFlow.setWoBizNo(wo.getBizNo());
								inFlow.setWoBizType(wo.getWoType());
								inFlow.setWoBizLineNo(line.getLineNo());
								inFlow.setLotNo(line.getLotNo());
								inFlow.setSubLotIndex(line.getSubLotIndex());
								JpaUtil.save(inFlow);
							}
						}
					}
				}
			}*/
			return bizOrderService.updateOrderStatus(mo, OrderStatusEnums.OrderStatus.CLEARED);
		}else{
			return Result.error("非完成状态不可结算");
		}
	}
}
